import { Component, ScrollView, _decorator, Node, UITransform, v3, Size, Vec3, Widget, error, instantiate } from "cc";
import ScrollViewItemBase from "./ScrollViewItemBase";

const { ccclass, property } = _decorator;

@ccclass
export default class LoopScrollView extends Component {


    private _scrollView: ScrollView = null;

    //实际创建的项数量
    private _spawnCount = 0;

    private _totalCount = 0;

    //项之间的间隔大小
    private _spacing = 0;

    private _nodeItem: Node = null;

    private _bufferZone = 0;

    private _lastContentPosY = 0;

    private _nodeContentPosYOriginal = 0;

    private _nodeContent: Node = null;

    private _nodeItems: Node[] = [];// 存储实际创建的项数组

    /**>1代表是多行多列循环列表 */
    private _childNums = 1;

    private _poolName = null;


    public init(nodeItem: Node, poolname: string, scrollView: ScrollView, _childNums = 1, _spacing = 10, base: typeof ScrollViewItemBase) {
        this._scrollView = scrollView;
        this._childNums = _childNums;
        this._spacing = _spacing;
        if (!nodeItem.getComponent(base)) {
            nodeItem.addComponent(base);
        }
        this._poolName = poolname;
        this._nodeItem = nodeItem;
        this._spawnCount = Math.ceil(this._scrollView.node.getComponent(UITransform).height / nodeItem.getComponent(UITransform).height) + 1;

        this._initContent();
        // 使用这个变量来判断滚动操作是向上还是向下
        this._lastContentPosY = 0;
        // 设定缓冲矩形的大小为实际创建项的高度累加，当某项超出缓冲矩形时，则更新该项的显示内容
        this._bufferZone = this._spawnCount * (this._nodeItem.getComponent(UITransform).height + this._spacing) / 2;

        this._scrollView.node.on('scrolling', this._onScrolling, this);

        console.log('loop scroll view init', this._nodeContent, this._scrollView);
    };

    private _onScrolling() {
        let _nodeItems = this._nodeItems;
        // 如果当前_nodeContent的y坐标小于上次记录值，则代表往下滚动，否则往上。
        let isDown = this._scrollView.content.position.y < this._lastContentPosY;
        // 实际创建项占了多高（即它们的高度累加）
        let offset = (this._nodeItem.getComponent(UITransform).height + this._spacing) * _nodeItems.length;
        let newY = 0;

        // 遍历数组，更新item的位置和显示
        for (let i = 0; i < _nodeItems.length; ++i) {
            let itemNode = _nodeItems[i];
            let viewPos = this._getPositionInView(itemNode);
            if (isDown) {
                // 提前计算出该item的新的y坐标
                newY = itemNode.position.y + offset;
                // 如果往下滚动时item已经超出缓冲矩形，且newY未超出_nodeContent上边界，
                // 则更新item的坐标（即上移了一个offset的位置），同时更新item的显示内容
                if (viewPos.y < -this._bufferZone && newY < 0) {
                    itemNode.setPosition(itemNode.position.x, newY, 0);
                    let item: ScrollViewItemBase = itemNode.getComponent(ScrollViewItemBase);
                    let itemId = item.itemID - _nodeItems.length; // update item id
                    this._updateItem(itemId, item);
                }
            } else {
                // 提前计算出该item的新的y坐标
                newY = itemNode.position.y - offset;
                // 如果往上滚动时item已经超出缓冲矩形，且newY未超出_nodeContent下边界，
                // 则更新item的坐标（即下移了一个offset的位置），同时更新item的显示内容
                if (viewPos.y > this._bufferZone && newY > -this._nodeContent.getComponent(UITransform).height) {
                    itemNode.setPosition(itemNode.position.x, newY, 0);
                    let item: ScrollViewItemBase = itemNode.getComponent(ScrollViewItemBase);
                    let itemId = item.itemID + _nodeItems.length;
                    this._updateItem(itemId, item);
                }
            }
        }

        // 更新_lastContentPosY和总项数显示
        this._lastContentPosY = this._scrollView.content.position.y;
    }

    private _initContent() {
        if (this._nodeContent == null) {
            this._nodeContent = this._scrollView.content;
            this._nodeContentPosYOriginal = this._nodeContent.position.y;

            // 获取整个列表的高度
            let scriptName: ScrollViewItemBase = this._nodeItem.getComponent(ScrollViewItemBase);
            this._childNums = scriptName.mChildNums;
        }
        this.recoveryChildren(this._nodeItems, this._poolName);
        this._nodeItems = [];
        let layoutNums = Math.ceil(this._totalCount / this._childNums);
        this._nodeContent.getComponent(UITransform).height = layoutNums * (this._nodeItem.getComponent(UITransform).height + this._spacing) + this._spacing;
        for (let i = 0; i < this._spawnCount; ++i) { // spawn _nodeItems, we only need to do this once
            let item = instantiate(this._nodeItem);
            this._nodeContent.addChild(item);
            item.getComponent(ScrollViewItemBase).init()
            // 设置该item的坐标（注意父节点_nodeContent的Anchor坐标是(0.5, 1)，所以item的y坐标总是负值）
            item.setPosition(0, -item.getComponent(UITransform).height * (0.5 + i) - this._spacing * (i + 1));
            let scriptName: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
            // 默认先关闭, 不需要调updateItem
            //this._updateItem(i, scriptName);
            item.active = false;
            this._nodeItems.push(item);
        }
    };

    private convertLocalPosition(sourceNode: Node, targetNode: Node, localPosition: Vec3): Vec3 {
        const worldPosition = sourceNode.getComponent(UITransform).convertToWorldSpaceAR(localPosition);
        const targetLocalPosition = targetNode.getComponent(UITransform).convertToNodeSpaceAR(worldPosition);
        return targetLocalPosition;
    }
    // 返回item在ScrollView空间的坐标值
    private _getPositionInView(item) {
        return this.convertLocalPosition(item.parent, this._scrollView.node, v3(item.position.x, item.position.y, 0));
    };

    private _addItem(addNums) {
        let newTotalCount = Math.max(0, this._totalCount + addNums);
        let oldLayoutNums = Math.ceil(this._totalCount / this._childNums);
        let newLayoutNums = Math.ceil(newTotalCount / this._childNums);
        let addNums_Show = Math.min(newLayoutNums, this._spawnCount);
        if (oldLayoutNums < this._spawnCount) {
            //显示小于实际创建_spawnCount
            for (let i = oldLayoutNums; i < addNums_Show; i++) {
                let item = this._nodeItems[i];
                item.active = true;
                let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
                this._updateItem(i, itemScrip);
            }
        }

        //多行多列-判断是否在视框位置添加,是的话判断是否可以显示一行或刷新一行
        if (this._childNums > 1) {
            //显示
            if (newLayoutNums <= this._spawnCount) {
                let item = this._nodeItems[newLayoutNums - 1];
                item.active = true;
                let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
                let itemId = newLayoutNums - 1;
                this._updateItem(itemId, itemScrip);
            } else {
                //刷新
                let layoutIndex = newLayoutNums % this._childNums - 1;
                layoutIndex = layoutIndex < 0 ? this._spawnCount - 1 : layoutIndex;
                let item = this._nodeItems[layoutIndex];
                let maxYItem = this._getItemAtBottom();
                //如果当前位置正好也在视框内(最底部item)
                if (maxYItem == item) {
                    //且当前子物体全部激活状态则不需要更新
                    let childNodeActiveNums = this._getItemChildActiveNums(item);
                    if (childNodeActiveNums >= this._childNums) {
                        return;
                    }
                    let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
                    let itemId = newLayoutNums - 1;
                    this._updateItem(itemId, itemScrip);
                }
            }
        }
        this._nodeContent.getComponent(UITransform).height = (newLayoutNums) * (this._nodeItem.getComponent(UITransform).height + this._spacing) + this._spacing; // get total _nodeContent height
        this._totalCount = newTotalCount;
    };

    private _removeItem(removeNums) {
        if (this._totalCount == 0) {
            return;
        }
        let oldLayoutNums = Math.ceil(this._totalCount / this._childNums);
        let newTotalCount = Math.max(0, this._totalCount - removeNums);
        let newLayoutNums = Math.ceil(newTotalCount / this._childNums);
        if (newLayoutNums < this._spawnCount) {
            //隐藏小于实际创建_spawnCount
            for (let i = newLayoutNums; i < this._spawnCount; i++) {
                let item = this._nodeItems[i];
                item.active = false;
            }
        }
        //多行多列-判断是否在视框位置删除,是的话判断是否可以隐藏一行或刷新一行
        if (this._childNums > 1) {
            //找到当前数据长度对应的item索引
            let layoutIndex = oldLayoutNums % this._childNums - 1;
            layoutIndex = layoutIndex < 0 ? this._spawnCount - 1 : layoutIndex;
            let item = this._nodeItems[layoutIndex];
            let maxYItem = this._getItemAtBottom();
            //隐藏-如果当前位置正好也在视框内(最底部)
            if (maxYItem == item || maxYItem.active == false) {
                if (newLayoutNums < oldLayoutNums) {
                    item.active = false;
                } else {
                    //刷新
                    let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
                    let itemId = oldLayoutNums - 1;
                    this._updateItem(itemId, itemScrip);
                }
            }
        }

        this._nodeContent.getComponent(UITransform).height = (newLayoutNums) * (this._nodeItem.getComponent(UITransform).height + this._spacing) + this._spacing; // get total _nodeContent height
        this._totalCount = newTotalCount;
        this._moveBottomItemToTop();
        this._refreshItemDB();
    };

    private _moveBottomItemToTop() {
        let offset = (this._nodeItem.getComponent(UITransform).height + this._spacing) * this._nodeItems.length;
        let length = this._nodeItems.length;
        let item = this._getItemAtBottom();

        // whether need to move to top
        if (item.position.y + offset < 0 && (this._getItemChildActiveNums(item) <= 0 || item.active == false)) {
            let itemComp: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
            //防止单行单列中间移除露馅,则不把底部变换到顶部
            if (this._childNums <= 1 && itemComp.itemID < this._totalCount) {
                return;
            }
            let itemId = itemComp.itemID - length;
            this._updateItem(itemId, itemComp);
            item.setPosition(item.position.x, item.position.y + offset, 0)
        }
    }

    private _getItemChildActiveNums = (item: Node) => {
        let childNodeActiveNums = 0;
        let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
        for (let i = 0; i < itemScrip.mChildNode.length; i++) {
            let childNode = itemScrip.mChildNode[i];
            if (childNode == null) {
                error("需要在单项onLoad赋值子物体");
                return;
            }
            if (childNode.active == true) {
                childNodeActiveNums += 1;
            }
        }
        return childNodeActiveNums;
    };

    private _getItemAtBottom() {
        let item = this._nodeItems[0];
        for (let i = 1; i < this._nodeItems.length; ++i) {
            if (item.position.y > this._nodeItems[i].position.y) {
                item = this._nodeItems[i];
            }
        }
        return item;
    }

    /**索引排序后刷数据层 */
    private _refreshItemDB() {
        this._nodeItems.forEach(item => {
            if (item.active) {
                let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
                this._updateItem(itemScrip.itemID, itemScrip);
            }
        });
    }

    private _updateItem(id, scrollViewItemBase: ScrollViewItemBase) {
        if (this._data === null || !this._data.hasOwnProperty(id)) {
            scrollViewItemBase.node.active = false;
            return;
        }
        scrollViewItemBase.updateItem(id, this._data[id]);
    }

    private _data: any = null;

    /**数据层改变刷新_totalCount与UI */
    public setData(data) {
        this._scrollView.stopAutoScroll();
        this._removeItem(this._totalCount);
        // 移除后重新初始化
        this._initContent();
        this._data = data;
        let newTotalCount = data.length;
        this._addItem(newTotalCount);
        // 如果为空，设置为空
        if (newTotalCount <= 0) {
            for (let i = 0; i < this._nodeContent.children.length; i++) {
                this._nodeContent.children[i].active = false;
            }
        }
    }
    public updatedata(data) {
        this._data = data;
        this._nodeItems.forEach(item => {
            if (item.active) {
                let itemScrip: ScrollViewItemBase = item.getComponent(ScrollViewItemBase);
                this._updateItem(itemScrip.itemID, itemScrip);
            }
        });
    }
    private recoveryChildren(children, poolName) {
        if (children.length <= 0) {
            return;
        }
        let nodeList = [];
        for (let i = 0; i < children.length; i++) {
            nodeList.push(children[i]);
        }
        for (let i = 0; i < nodeList.length; i++) {
            nodeList[i].removeFromParent()
        }
    }
}